package com.sdy.usercenter.biz.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sdy.auth.api.model.UserInfo;
import com.sdy.common.model.BizException;
import com.sdy.common.model.PageQuery;
import com.sdy.common.model.PageResult;
import com.sdy.common.utils.Assert;
import com.sdy.common.utils.DateUtil;
import com.sdy.common.utils.StringUtil;
import com.sdy.mq.service.MqProducerService;
import com.sdy.usercenter.biz.constants.MqConstants;
import com.sdy.usercenter.biz.mapper.SysRoleMapper;
import com.sdy.usercenter.biz.mapper.SysUserRoleMapper;
import com.sdy.usercenter.biz.model.SysDept;
import com.sdy.usercenter.biz.model.SysLog;
import com.sdy.usercenter.biz.model.SysRole;
import com.sdy.usercenter.biz.model.SysUser;
import com.sdy.usercenter.biz.mapper.SysUserMapper;
import com.sdy.usercenter.biz.model.SysUserDept;
import com.sdy.usercenter.biz.model.SysUserRole;
import com.sdy.usercenter.biz.model.vo.UserRoleVO;
import com.sdy.usercenter.biz.service.SysDeptService;
import com.sdy.usercenter.biz.service.SysUserDeptService;
import com.sdy.usercenter.biz.service.SysUserService;
import com.sdy.mvc.service.impl.BaseServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户基础信息表 服务实现类
 * </p>
 *
 * @author zzq
 * @since 2019-06-14
 */
@Slf4j
@Service
public class SysUserServiceImpl extends BaseServiceImpl<SysUser> implements SysUserService {
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private SysUserDeptService sysUserDeptService;
    @Autowired
    private MqProducerService mqProducerService;
    @Autowired
    private SysDeptService sysDeptService;
    @Autowired
    private SysRoleMapper sysRoleMapper;
    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;

    @Override
    public void saveUser(SysUser sysUser) throws BizException {
        Assert.isTrue(lambdaQuery().eq(SysUser::getIdCard, sysUser.getIdCard()).count() > 0, "身份证号已经被使用");
        if (sysUser.getDeptId() != null) {
            SysDept dept = sysDeptService.getById(sysUser.getDeptId());
            Assert.isTrue(dept == null || StringUtil.isBlank(dept.getSuffix()), "请先完善组织信息");
        }
        save(sysUser);
        sysUserDeptService.save(new SysUserDept().setUserId(sysUser.getId()).setAdmin(2).setCreateTime(new Date()).setDeptId(sysUser.getDeptId()));
    }

    @Override
    public void updateUser(SysUser user) throws BizException {
        Assert.isTrue(lambdaQuery().eq(SysUser::getIdCard, user.getIdCard()).ne(SysUser::getId, user.getId()).count() > 0, "身份证号已经被使用");
        updateById(user);
        if (user.getDeptId() != null) {
            SysDept dept = sysDeptService.getById(user.getDeptId());
            Assert.isTrue(dept == null || StringUtil.isBlank(dept.getSuffix()), "请先完善组织信息");
            // 用户部门
            List<SysUserDept> rootUserDeptList = sysUserDeptService.listByExample(new SysUserDept().setUserId(user.getId()).setAdmin(2));
            List<Integer> toAddDeptIdList = new ArrayList<>();
            if (rootUserDeptList.stream().noneMatch(item -> item.getDeptId().equals(user.getDeptId()))) {
                toAddDeptIdList.add(user.getDeptId());
            }
            List<Integer> toDelUserDeptIdList = rootUserDeptList.stream()
                    .filter(item -> !item.getDeptId().equals(user.getDeptId()))
                    .map(SysUserDept::getId).collect(Collectors.toList());
            if (!toAddDeptIdList.isEmpty()) {
                toAddDeptIdList.forEach(item -> {
                    sysUserDeptService.save(new SysUserDept().setUserId(user.getId()).setAdmin(2).setCreateTime(new Date()).setDeptId(user.getDeptId()));
                });
            }
            if (!toDelUserDeptIdList.isEmpty()) {
                sysUserDeptService.removeByIds(toDelUserDeptIdList);
            }
            String suffix = getUserDeptSuffix(null, user.getDeptId());
            lambdaUpdate()
                    .eq(SysUser::getId, user.getId())
                    .setSql(String.format("login_name=concat(simple_login_name,'%s')", suffix))
                    .update();
        }
    }

    @Override
    public void updateWithNullTime(SysUser user) throws BizException {
        updateById(user);
        if (user.getExpireTime() == null) {
            sysUserMapper.updateExpireTimeNull(user.getId());
        }
    }
    
    @Override
    public IPage<SysUser> pageUserWithRole(IPage<SysUser> page, Map<String, Object> query, Integer roleId, Boolean contain) {
        query.put("startRecord", (page.getCurrent() - 1) * page.getSize());
        query.put("endRecord", page.getSize());
        query.put("roleId", roleId);

        if (contain) {
            Integer count = sysUserMapper.pageUserWithRoleCount(query);
            if (count > 0) {
                List<SysUser> list = sysUserMapper.pageUserWithRole(query);
                return new Page<SysUser>(page.getCurrent(), page.getSize(), count).setRecords(list);
            } else {
                return new Page<SysUser>(page.getCurrent(), page.getSize(), count).setRecords(new ArrayList<>());
            }
        } else {
            Integer count = sysUserMapper.pageUserWithoutRoleCount(query);
            if (count > 0) {
                List<SysUser> list = sysUserMapper.pageUserWithoutRole(query);
                return new Page<SysUser>(page.getCurrent(), page.getSize(), count).setRecords(list);
            } else {
                return new Page<SysUser>(page.getCurrent(), page.getSize(), count).setRecords(new ArrayList<>());
            }
        }
    }

    @Override
    public void modifyPassword(Integer userId, String password) {
        SysUser vo = new SysUser();
        vo.setId(userId);
        vo.setPassword(password);
        sysUserMapper.updateById(vo);
    }

    @Override
    public void openAccount(SysUser vo, UserInfo opUserInfo, String ip) throws Exception {
        updateWithNullTime(vo);
        // 日志消息
        SysUser user = getById(vo.getId());
        mqProducerService.send(MqConstants.Tags.TAG_OP_LOG,
                SysLog.LogType.OPEN_ACCOUNT.getTypeS().concat(MqConstants.SEP_TOKEN)
                        .concat(opUserInfo.getUserId().toString()).concat(MqConstants.SEP_TOKEN)
                        .concat(DateUtil.formatTime(new Date())).concat(MqConstants.SEP_TOKEN)
                        .concat(ip).concat(MqConstants.SEP_TOKEN)
                        .concat(opUserInfo.getUserName() + " 开户：" + user.getName() + " [" + user.getId() + "]")
        );
        // 开户消息
        mqProducerService.send(MqConstants.Tags.TAG_OPENACCOUNT,
                user.getId().toString().concat(MqConstants.SEP_TOKEN)
                .concat(DateUtil.formatTime(user.getEffectTime()))
        );
    }

    @Override
    public PageResult<SysUser> pageUserInDept(PageQuery page, Integer deptId, String username, Boolean recursively) {
        Map<String, Object> query = new HashMap<>();
        query.put("startRecord", (page.getCurrent() - 1) * page.getSize());
        query.put("endRecord", page.getSize());
        if (StringUtil.isNotBlank(username)) {
            query.put("username", username);
        }
        SysDept dept = sysDeptService.getById(deptId);
        query.put("deptCode", dept.getCode());
        if (!recursively) {
            Integer count = sysUserMapper.pageUserInDeptCount(query);
            if (count > 0) {
                List<SysUser> list = sysUserMapper.pageUserInDept(query);
                return new PageResult<>(page, count, list);
            } else {
                return new PageResult<>(page, count, new ArrayList<>());
            }
        } else {
            Integer count = sysUserMapper.pageUserInDeptRCount(query);
            if (count > 0) {
                List<SysUser> list = sysUserMapper.pageUserInDeptR(query);
                return new PageResult<>(page, count, list);
            } else {
                return new PageResult<>(page, count, new ArrayList<>());
            }
        }
    }

    @Override
    public IPage<SysUser> pageUserWithApp(Page<SysUser> page, Map<String, Object> query, Integer appId, Boolean contain) {
        query.put("startRecord", (page.getCurrent() - 1) * page.getSize());
        query.put("endRecord", page.getSize());
        query.put("appId", appId);

        if (contain) {
            Integer count = sysUserMapper.pageUserWithAppCount(query);
            if (count > 0) {
                List<SysUser> list = sysUserMapper.pageUserWithApp(query);
                return new Page<SysUser>(page.getCurrent(), page.getSize(), count).setRecords(list);
            } else {
                return new Page<SysUser>(page.getCurrent(), page.getSize(), count).setRecords(new ArrayList<>());
            }
        } else {
            Integer count = sysUserMapper.pageUserWithoutAppCount(query);
            if (count > 0) {
                List<SysUser> list = sysUserMapper.pageUserWithoutApp(query);
                return new Page<SysUser>(page.getCurrent(), page.getSize(), count).setRecords(list);
            } else {
                return new Page<SysUser>(page.getCurrent(), page.getSize(), count).setRecords(new ArrayList<>());
            }
        }
    }

    @Override
    public boolean checkUsernameUnique(String username, Integer userId, Integer deptId) {
        if (username == null) {
            username = "";
        }
        String suffix = getUserDeptSuffix(userId, deptId);
        return lambdaQuery()
                .eq(SysUser::getLoginName, username.concat(suffix))
                .ne(userId != null, SysUser::getId, userId)
                .count() <= 0;
    }

    @Override
    public String getUserDeptSuffix(Integer userId, Integer deptId) {
        if (deptId == null) {
            SysUserDept userDept = sysUserDeptService.lambdaQuery().eq(SysUserDept::getUserId, userId).eq(SysUserDept::getAdmin, 2).one();
            deptId = userDept.getDeptId();
        }
        List<SysDept> dl = sysDeptService.getDeptAccessorList(deptId);
        if (dl.isEmpty() || dl.stream().filter(item -> StringUtil.isNotBlank(item.getSuffix())).count() <= 0) {
            return "";
        }
        return ".".concat(dl.stream().filter(item -> StringUtil.isNotBlank(item.getSuffix())).map(SysDept::getSuffix).collect(Collectors.joining(".")));
    }

    @Override
    public List<UserRoleVO> listUserRole(Integer userId, Boolean authOnly) {
        List<SysRole> allRoleList = sysRoleMapper.selectList(new LambdaQueryWrapper<SysRole>());
        List<SysUserRole> userRoleList = sysUserRoleMapper.selectList(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, userId));
        Set<Integer> userRoleSet = userRoleList.stream().map(SysUserRole::getRoleId).collect(Collectors.toSet());
        return allRoleList.stream().filter(role -> !authOnly || userRoleSet.contains(role.getId())).map(role ->
                new UserRoleVO()
                        .setUserId(userId)
                        .setAuth(userRoleSet.contains(role.getId()))
                        .setEnabled(role.getState().equals(1))
                        .setRoleCode(role.getCode())
                        .setRoleId(role.getId())
                        .setRoleName(role.getName())).collect(Collectors.toList());
    }

    @Override
    public void updateUserRole(Integer userId, List<Integer> roleIdList) {
        // 新增角色id
        List<Integer> newUserRoleList = roleIdList == null ? new ArrayList<>() : roleIdList;
        // 原有角色
        List<SysUserRole> userRoleList = sysUserRoleMapper.selectList(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, userId));

        Iterator<SysUserRole> iter = userRoleList.iterator();
        while (iter.hasNext()) {
            SysUserRole item = iter.next();
            if (newUserRoleList.contains(item.getRoleId())) {
                iter.remove();
                newUserRoleList.remove(item.getRoleId());
            }
        }
        // 删除多余角色
        if (!userRoleList.isEmpty()) {
            sysUserRoleMapper.deleteBatchIds(userRoleList.stream().map(SysUserRole::getId).collect(Collectors.toList()));
        }
        // 增加新增角色
        if (!newUserRoleList.isEmpty()) {
            List<SysUserRole> toSaveList = newUserRoleList
                    .stream()
                    .map(item -> new SysUserRole().setUserId(userId).setRoleId(item).setCreateTime(new Date()))
                    .collect(Collectors.toList());
            for (SysUserRole item : toSaveList) {
                sysUserRoleMapper.insert(item);
            }
        }
    }
}
